package com.stone.starter.core.helper;

import org.apache.commons.lang3.tuple.ImmutablePair;

import java.util.*;

/**
 * 数据去重、分组帮助器
 *
 * @author Mr_wenpan@163.com 2021/07/29 09:20
 */
public abstract class DataUniqueHelper<T> {

    private final static int BATCH_SIZE = 100;

    public Map<String, T> filter(List<T> operationDataList, int batchSize) {
        return removeDuplicate(operationDataList, batchSize);
    }

    public Map<String, T> filter(List<T> operationDataList) {
        return removeDuplicate(operationDataList, BATCH_SIZE);
    }

    public Map<String, Set<T>> group(List<T> operationDataList, int batchSize) {
        return groupBy(operationDataList, batchSize);
    }

    public Map<String, Set<T>> group(List<T> operationDataList) {
        return groupBy(operationDataList, BATCH_SIZE);
    }

    /**
     * 比较方法，可覆盖方法对过滤的数据进行筛选操作，自己决定需要哪一个
     *
     * @param var     当前的值
     * @param nextVar 需要比较的值
     * @return 结果 {选择的值,舍弃的值}
     */
    protected ImmutablePair<T, T> choose(T var, T nextVar) {
        return ImmutablePair.of(var, nextVar);
    }

    /**
     * list集合按某个key进行分组
     *
     * @param operationDataList 待分组的list集合
     * @param batchSize         废弃数据批量处理阈值
     * @return java.util.Map<java.lang.String, java.util.Set < T>>
     * @author Mr_wenpan@163.com 2021/7/29 10:00 上午
     */
    private Map<String, Set<T>> groupBy(List<T> operationDataList, int batchSize) {

        if (operationDataList == null || operationDataList.isEmpty()) {
            return null;
        }

        Map<String, Set<T>> groupMap = new HashMap<>();
        List<T> abandonVar = new ArrayList<>();
        for (T var : operationDataList) {
            String key = mapKey(var);
            // key为空的话默认当废弃数据处理
            if (key == null || key.isEmpty()) {
                abandonVar.add(var);
                continue;
            }
            // 如果在map中不存在该值，则添加
            if (groupMap.get(key) == null) {
                // 创建一个set集合，put到map中
                Set<T> value = new HashSet<>();
                value.add(var);
                groupMap.put(key, value);
                continue;
            }
            // 如果map中已经存在了，则把该元素添加到该key对应的list中
            groupMap.get(key).add(var);

            // 废弃数据达到指定的处理阈值后，按照一定数据维度，做数据操作
            if (abandonVar.size() == batchSize) {
                abandonBatchOperation(abandonVar);
                abandonVar.clear();
            }
        }
        if (abandonVar.size() > 0) {
            abandonBatchOperation(abandonVar);
            abandonVar.clear();
        }

        return groupMap;
    }

    /**
     * 去除重复
     *
     * @param operationDataList 需要去重的集合
     * @param batchSize         废弃数据批量处理阈值
     * @return java.util.Map<java.lang.String, org.apache.poi.ss.formula.functions.T>
     * @author Mr_wenpan@163.com 2021/7/29 9:49 上午
     */
    private Map<String, T> removeDuplicate(List<T> operationDataList, int batchSize) {

        if (operationDataList == null || operationDataList.isEmpty()) {
            return null;
        }

        Map<String, T> resultMap = new HashMap<>();
        List<T> abandonVar = new ArrayList<>();
        for (T currVar : operationDataList) {
            // 获取到map的key
            String key = mapKey(currVar);
            // 如果key为空，则认为是无效的废弃数据
            if (key == null || key.isEmpty()) {
                abandonVar.add(currVar);
                continue;
            }
            // 通过key去map中查找，如果没有则添加
            if (resultMap.get(key) == null) {
                resultMap.put(key, currVar);
                continue;
            }
            // 如果map中已经存在对应的value，则由用户决定选择哪一个
            ImmutablePair<T, T> pair = choose(resultMap.get(key), currVar);
            resultMap.put(key, pair.left);
            abandonVar.add(pair.right);

            // 废弃数据达到指定的处理阈值后，按照一定数据维度，做数据操作
            if (abandonVar.size() == batchSize) {
                abandonBatchOperation(abandonVar);
                abandonVar.clear();
            }
        }
        if (abandonVar.size() > 0) {
            abandonBatchOperation(abandonVar);
            abandonVar.clear();
        }

        return resultMap;
    }

    /**
     * 对重复的废弃数据进行自定义操作
     *
     * @param abandonVar 重复数据集合
     * @return void
     * @author Mr_wenpan@163.com 2021/7/29 9:48 上午
     */
    protected void abandonBatchOperation(List<T> abandonVar) {

    }

    protected abstract String mapKey(T var);
}
